/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2021 Huawei Technologies Co., Ltd */

#ifndef HINIC3_RX_H
#define HINIC3_RX_H

/*
 * 文件说明:
 * 本头文件定义了 HINIC3 网卡驱动的接收（RX）路径相关的数据结构、宏定义以及
 * 对外导出的 RX 队列管理与轮询接口。仅包含类型与原型声明，不包含实现。
 *
 * 主要内容:
 * - 硬件 RX CQE 校验错误位的宏定义
 * - RX 队列统计、WQE 上下文与 RX 队列控制结构体
 * - RX 资源动态封装结构体
 * - RX 队列的分配、释放、配置、NAPI 轮询、统计获取与健康检查等函数原型
 *
 * 并发与上下文:
 * - 大多数 RX 队列读写由 NAPI poll 上下文与控制路径（netdevice/ethtool/复位）并发访问
 * - 统计项通过 u64_stats_sync 进行 64 位同步保证
 * - DMA 缓冲区与 CQE/WQE 内存遵循内核 DMA 映射与缓存一致性要求
 */

#include <linux/types.h>
#include <linux/device.h>
#include <linux/mm_types.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/u64_stats_sync.h>

#include "hinic3_nic_io.h"
#include "hinic3_nic_qp.h"
#include "hinic3_nic_dev.h"

/*
 * RX CQE 硬件校验错误位定义
 * 说明:
 *  - 这些位来自硬件填充的 CQE（Completion Queue Entry），用于指示 IP/TCP/UDP 等
 *    协议层面的校验错误。驱动据此统计错误并决定是否标记 skb->ip_summed 或丢弃。
 */
#define HINIC3_RX_CSUM_IP_CSUM_ERR	BIT(0)  /* IP 头部校验和错误 */
#define HINIC3_RX_CSUM_TCP_CSUM_ERR	BIT(1)  /* TCP 校验和错误 */
#define HINIC3_RX_CSUM_UDP_CSUM_ERR	BIT(2)  /* UDP 校验和错误 */
#define HINIC3_RX_CSUM_IGMP_CSUM_ERR	BIT(3)  /* IGMP 校验和错误 */
#define HINIC3_RX_CSUM_ICMPV4_CSUM_ERR	BIT(4)  /* ICMPv4 校验和错误 */
#define HINIC3_RX_CSUM_ICMPV6_CSUM_ERR	BIT(5)  /* ICMPv6 校验和错误 */
#define HINIC3_RX_CSUM_SCTP_CRC_ERR	BIT(6)  /* SCTP CRC 错误 */
#define HINIC3_RX_CSUM_HW_CHECK_NONE	BIT(7)  /* 硬件未执行校验（需软件处理） */
#define HINIC3_RX_CSUM_IPSU_OTHER_ERR	BIT(8)  /* 其他 IP/伪首部/未分类的校验异常 */

/*
 * 头部数据的单位定义:
 * 部分硬件描述符采用 2 字节（2B）为度量单位表达字段长度，此处宏用于便捷换算。
 */
#define HINIC3_HEADER_DATA_UNIT 2  /* 硬件头部长度单位为 2 字节 */

/**
 * struct hinic3_rxq_stats - RX 队列统计信息
 * 说明:
 * - 本结构在每个 RX 队列实例上维护，统计仅对该队列生效。
 * - 读取时建议使用 u64_stats_fetch_begin_irq/u64_stats_fetch_retry_irq 等配套 API。
 */
struct hinic3_rxq_stats {
    u64	packets;            /* 成功接收并上交协议栈的包数 */
    u64	bytes;              /* 成功接收的总字节数 */
    u64	errors;             /* 接收错误总数（汇总） */
    u64	csum_errors;        /* 校验和相关错误计数 */
    u64	other_errors;       /* 其他非校验类错误计数 */
    u64	dropped;            /* 驱动在提交前丢弃的包数 */
    u64	xdp_dropped;        /* XDP 程序执行后丢弃的包数 */
    u64	rx_buf_empty;       /* RQ 接收缓冲耗尽次数 */

    u64	alloc_skb_err;      /* 分配 SKB 失败次数 */
    u64	alloc_rx_buf_err;   /* 分配/映射 RX 缓冲失败次数 */
    u64	xdp_large_pkt;      /* 因包过大导致 XDP 无法处理的次数 */
    u64	restore_drop_sge;   /* 恢复过程中丢弃的分散段次数 */
    u64	rsvd2;              /* 预留，结构对齐/扩展 */

#ifdef HAVE_NDO_GET_STATS64
    struct u64_stats_sync		syncp; /* 64 位统计同步原语 */
#else
    struct u64_stats_sync_empty	syncp; /* 空同步占位（兼容老内核） */
#endif
};

/**
 * struct hinic3_rx_info - RX WQE 级别上下文信息
 * 说明:
 * - 该结构按队列深度进行数组分配，一一对应 RQ 中的每个 WQE。
 * - DMA 映射/解除映射需遵循 DMA API，避免重复映射或泄露。
 */
struct hinic3_rx_info {
    dma_addr_t			buf_dma_addr;  /* 数据缓冲区的 DMA 地址 */

    struct hinic3_rq_cqe		*cqe;          /* 指向对应的 CQE 虚拟地址 */
    dma_addr_t			cqe_dma;       /* CQE 的 DMA 物理地址 */
    struct page			*page;         /* 承载接收数据的页 */
    u32				page_offset;   /* 缓冲在页内的偏移 */
    u32				rsvd1;         /* 预留，对齐/扩展 */
    struct hinic3_rq_wqe		*rq_wqe;       /* 与之关联的 RQ WQE 指针 */
    struct sk_buff			*saved_skb;    /* 组包/合并暂存的 SKB */
    u32				skb_len;       /* saved_skb 当前累计长度 */
    u32				rsvd2;         /* 预留，对齐/扩展 */
};

/**
 * struct hinic3_rxq - 接收队列（RX Queue）控制块
 * 说明:
 * - ____cacheline_aligned: 确保按缓存行对齐，降低伪共享。
 * - 索引按 0..q_depth-1 循环，配合 q_mask 快速取模。
 */
struct hinic3_rxq {
    struct net_device		*netdev;               /* 所属 net_device */

    u16				q_id;                 /* 队列逻辑编号 */
    u16				rsvd1;                /* 预留，对齐 */
    u32				q_depth;              /* 队列深度（环大小） */
    u32				q_mask;               /* 索引掩码（q_depth-1） */

    u16				buf_len;              /* 单个接收缓冲有效长度 */
    u16				rsvd2;                /* 预留，对齐 */
    u32				rx_buff_shift;        /* 缓冲大小位移（1<<shift） */
    u32				dma_rx_buff_size;     /* 实际 DMA 缓冲尺寸 */

    struct hinic3_rxq_stats		rxq_stats;            /* 队列级统计 */
    u32				cons_idx;             /* SW 消费者索引（CI） */
    u32				delta;                /* 本地索引差值/调优项 */

    u32				irq_id;               /* 绑定的中断 ID */
    u16				msix_entry_idx;       /* MSI-X 表项索引 */
    u16				rsvd3;                /* 预留，对齐 */

    struct hinic3_rx_info		*rx_info;             /* WQE 上下文数组 */
    struct hinic3_io_queue		*rq;                  /* 接收 I/O 队列资源 */
#ifdef HAVE_XDP_SUPPORT
    struct bpf_prog			*xdp_prog;            /* 绑定的 XDP 程序 */
#endif

    struct hinic3_irq		*irq_cfg;             /* 中断配置对象 */
    u16				next_to_alloc;        /* 下个需补充缓冲的位置 */
    u16				next_to_update;       /* 下个需写回/更新的位置 */
    struct device			*dev;                 /* DMA 映射使用的 device */

    unsigned long			status;               /* 队列状态位集合 */
    dma_addr_t			cqe_start_paddr;      /* CQE 环起始物理地址 */
    void				*cqe_start_vaddr;     /* CQE 环起始虚拟地址 */

    u64				last_moder_packets;   /* 上次合并统计的报文数 */
    u64				last_moder_bytes;     /* 上次合并统计的字节数 */
    u8				last_coalesc_timer_cfg; /* 上次合并计时器配置 */
    u8				last_pending_limt;    /* 上次 pending limit */
    u16				restore_buf_num;      /* 恢复需补回的缓冲数 */
    u32				rsvd5;                /* 预留，对齐 */
    u64				rsvd6;                /* 预留，对齐（64 位） */

    u32				last_sw_pi;           /* 上次记录的软件 PI */
    u32				last_sw_ci;           /* 上次记录的软件 CI */

    u32				last_hw_ci;           /* 上次采样的硬件 CI */
    u8				rx_check_err_cnt;     /* 健康检查错误计数 */
    u8				rxq_print_times;      /* 打印次数/抑制计数 */
    u16				restore_pi;           /* 恢复流程的软件 PI */

    u64				last_packets;         /* 上次采样接收包计数 */
} ____cacheline_aligned;                                         /* 缓存行对齐 */

/**
 * struct hinic3_dyna_rxq_res - RX 队列动态资源封装
 * 说明:
 * - 用于抽象队列资源在功能切换或复位恢复时的保存与重用。
 */
struct hinic3_dyna_rxq_res {
    u16				next_to_alloc;       /* 下一补充位置（与 RXQ 对齐） */
    struct hinic3_rx_info		*rx_info;            /* RX WQE 上下文数组基址 */
    dma_addr_t			cqe_start_paddr;     /* CQE 环起始物理地址 */
    void				*cqe_start_vaddr;    /* CQE 环起始虚拟地址 */
};

/* 为 net_device 分配并初始化所有 RX 队列（不启动硬件） */
int hinic3_alloc_rxqs(struct net_device *netdev);  /* 返回 0 成功，负 errno 失败 */

/* 释放 net_device 的 RX 队列及其软资源（需在队列停止/NAPI 关闭后调用） */
void hinic3_free_rxqs(struct net_device *netdev);  /* 无返回值 */

/* 分配/映射 RX 队列的硬件相关资源（CQE/WQE/缓冲等） */
int hinic3_alloc_rxqs_res(struct hinic3_nic_dev *nic_dev,  /* NIC 设备抽象 */
              u16 num_rq,                      /* 接收队列数量 */
              u32 rq_depth,                    /* 每队列环深度 */
              struct hinic3_dyna_rxq_res *rxqs_res); /* 输出资源数组 */

/* 释放 RX 队列的硬件相关资源（需确保硬件已停止访问） */
void hinic3_free_rxqs_res(struct hinic3_nic_dev *nic_dev,  /* NIC 设备抽象 */
              u16 num_rq,                      /* 接收队列数量 */
              u32 rq_depth,                    /* 每队列环深度 */
              struct hinic3_dyna_rxq_res *rxqs_res); /* 资源数组 */

/* 按给定参数配置 RX 队列（绑定资源、初始化属性/门铃等） */
int hinic3_configure_rxqs(struct hinic3_nic_dev *nic_dev,  /* NIC 设备抽象 */
              u16 num_rq,                      /* 队列数量 */
              u32 rq_depth,                    /* 环深度 */
              struct hinic3_dyna_rxq_res *rxqs_res); /* 已分配资源 */

/* 配置 net_device 的 RX 行为（MTU/RSS/DCB 等），dcb_en 非 0 表示启用 DCB */
int hinic3_rx_configure(struct net_device *netdev, u8 dcb_en);  /* 返回 0 成功 */

/* 移除/回滚 RX 相关配置（设备关闭或复位前） */
void hinic3_rx_remove_configure(struct netdevice *netdev);  /* 回滚 RX 配置 */

/* NAPI 轮询函数，处理 RX 完成并补充缓冲，返回处理的报文数 */
int hinic3_rx_poll(struct hinic3_rxq *rxq, int budget);  /* 0..budget */

/* 获取 RX 队列统计快照（使用 u64_stats 同步，读取不清零） */
void hinic3_rxq_get_stats(struct hinic3_rxq *rxq,          /* 目标队列 */
              struct hinic3_rxq_stats *stats); /* 输出统计 */

/* 清零 RX 队列统计（不影响外部聚合） */
void hinic3_rxq_clean_stats(struct hinic3_rxq_stats *rxq_stats);  /* 归零统计 */

/* RX 队列健康检查/恢复工作回调（检查推进/缓冲/CQE 异常等） */
void hinic3_rxq_check_work_handler(struct work_struct *work);  /* 工作队列回调 */

#endif
